{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# LOCCNet：用于 LOCC 协议设计的机器学习框架 \n",
    "\n",
    "<em> Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved. </em>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 概述\n",
    "\n",
    "量子纠缠在量子通信、量子计算以及其他量子技术中是一种很重要的资源。因此，能否在这些领域构建出实际的应用，很大程度上取决于我们能否有效地利用量子纠缠这一资源。在 NISQ （noisy intermediate-scale quantum）时代，通过量子网络实现两个节点之间直接通讯量子信息是一项艰巨的任务。所以在当前阶段，通过本地操作和经典通讯（LOCC）[1] 来完成特定任务，是比全局操作（global operation）更为有效的方式。所谓本地操作和经典通讯，是指几个空间上分离的参与者只能在自己的实验室中执行本地操作，然后通过经典通讯的方式传递他们经典信息（可以是测量结果）。然而，设计 LOCC 协议来进行纠缠操作以及分布式量子信息处理是非常具有挑战性的，因为 LOCC 的结构通常很复杂并且很难用数学方法描述。为了更好地探索如何在近期量子设备上利用量子纠缠资源以及从长远角度来看进行分布式量子信息处理，我们设计了 **LOCCNet**，一种用于 LOCC 协议设计的机器学习框架 [2]。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 什么是 LOCC？\n",
    "\n",
    "正如上面所描述的，LOCC 指代的是本地操作和经典通讯（local operations and classical communication），即一个多量子比特系统分配给位于不同位置的多个实验室（参与方）。假如有 $N$ 实验室，每个实验室只能做对他们手中的子系统 $k \\in [1,\\cdots,N]$ 做量子操作 $\\{\\mathcal{E}^{(k)}_j\\}_{j=0}^{r}$。这些实验室之间允许传输包括测量结果在内的经典信息。LOCC 协议通常是根据通讯的轮数 $r$ 和实验室的数量 $N$ 进行分类的，记为 LOCC$_r(N)$。比如量子隐形传态协议 [3] 就是一个一轮通讯两个参与方的协议 LOCC$_1(2)$，参与的两方通常命名为 Alice 和 Bob。这个协议的任务是把一个未知的量子态 $\\lvert\\psi\\rangle$ 从 Alice 传输给 Bob，图 1 所示的流程图具体阐述了如何实现这一任务。\n",
    "\n",
    "\n",
    "<img src=\"figures/teleportation-fig-circuit.jpg\" width=\"52%\" align = \"left\"/></center> <center><img src=\"figures/LOCC-fig-controltree.png\" width=\"48%\" align = \"right\"/> &nbsp;  \n",
    "<div style=\"text-align:center\">图 1：量子隐形传态协议的电路图（左）和树状图（右），其中 Alice 的测量结果 $m_1, m_2 \\in \\{0,1\\}$ </div>\n",
    "\n",
    "在量子隐形传态中，只有 Alice 对自己的量子比特进行了测量，Bob 的所有本地操作均取决于 Alice 的测量结果 $m_1m_2 \\in \\{00,01,10,11\\}$。当 $ k ^\\text{th}$ 一方的测量结果（$ m_1m_2 ... m_n $）控制着后面的本地操作时，我们称这类 LOCC 协议为 **Control-Type**。当 Alice 和 Bob 都对自己手中的量子比特进行测量时，协议就会变得复杂起来，因为他们可以选择合作并决定下一步做什么，这种协议被我们称之为 **Cooperation-Type**。比如图 2 中描述的纠缠蒸馏协议，关于该协议的详细讨论请参考教程 [BBPSSW 协议](./EntanglementDistillation_BBPSSW_CN.ipynb)。\n",
    "\n",
    "\n",
    "<img src=\"figures/LOCC-fig-BBPSSW.png\" width=\"52%\" align = \"left\"/></center> <center><img src=\"figures/LOCC-fig-cooptree.png\" width=\"48%\" align = \"right\"/> &nbsp;  \n",
    "<div style=\"text-align:center\">图 2：BBPSSW 蒸馏协议是一种 Cooperation-Type LOCC 协议。左图是电路图，右图是树状图，$m_1^{(1)}, m_1^{(2)} \\in \\{0,1\\}$，$m_j^{(k)}$ 表示的是第 $k^\\text{th}$ 参与方的测量结果。当测量结果为 $m_1^{(1)}m_1^{(2)} \\in \\{01,10\\}$ 时，判定协议失败。特别地，这里的本地操作为 $\\mathcal{E}_{0}^{(1)} = \\mathcal{E}_{0}^{(2)} = \\text{CNOT}$ 和 $\\mathcal{E}_{1}^{(1)} = \\mathcal{E}_{1}^{(2)} = I$。</div>\n",
    "\n",
    "    \n",
    "这些协议看上去十分简单，但是当参与方增多而且通讯轮数变多时，想要找到每一个参与方的最优的本地操作就会变得十分困难。现在我们大致了解了为什么说设计一个 LOCC 协议是一项艰巨的任务。即使如此困难，仍有许多重要的 LOCC 协议被科学家提了出来，比如：纠缠蒸馏（entanglement distillation） [4-5]，纠缠转换（entanglement swapping） [6-7] 等。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## LOCCNet 的设计理念\n",
    "\n",
    "我们从机器学习解决量子多体问题 [8] 以及预测蛋白质折叠结构 [9] 受到启发，使用机器学习的方法从众多可能的结果中搜寻最优的 LOCC 协议。为了实现上述目标，我们利用量子神经网络（quantum neural networks, QNN）表示每个本地操作 $\\mathcal{E}^{(k)}_j$，这也就意味着树状图中的每个节点都代表着一个量子神经网络（QNN），也可以称为参数化量子电路（parameterized quantum circuit, PQC）$U(\\boldsymbol \\theta)$。在 Paddle Quantum 中，我们提供多种 QNN 模板以减少用户的学习成本。在设置 QNN 之后，我们便可以规划如何测量和通讯。下面需要做的就是学习目标函数，通常情况下，我们把目标函数编码成损失函数 $L$。举个例子，在量子隐形传态协议中，我们的学习目标是最大化 Alice 想要传输的态 $|\\psi\\rangle$ 和 Bob 最终得到的态 $|\\phi\\rangle$ 之间的保真度，也就是说 $L \\equiv \\sum_{m_1m_2} \\big(1- F(|\\psi\\rangle, |\\phi\\rangle)\\big)$。根据所处理的任务不同，损失函数会有相应的变化。最后一步，使用经典的优化方法（主要是梯度下降）来训练 QNN 中的参数。优化完成后，我们就获得了一个近似最优的 LOCC 协议。从使用者的角度来说，LOCCNet 这样一个框架可以极大地减少设计 LOCC 协议所用的时间，而且得到的协议也是很容易被实验验证。\n",
    "\n",
    "\n",
    "**注释：** 当前版本下，LOCCNet 仅支持密度矩阵形式。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 功能简介"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这一部分，我们将解释 LOCCNet 的主要函数，让读者明白如何使用该框架。首先，我们展示一段伪代码：\n",
    "\n",
    "\n",
    "```python\n",
    "from paddle_quantum.locc import LoccNet\n",
    "\n",
    "class Net(LoccNet):\n",
    "    def __init__(self):\n",
    "        super(Net, self).__init__()\n",
    "        # Step 0: 初始化系统\n",
    "        # Step 1: 初始化 QNN 参数\n",
    "        # Step 2: 设置初始量子态\n",
    "        \n",
    "    def forward(self):\n",
    "        # Step 3: 定义并执行 QNNs\n",
    "        # Step 4: 定义 protocol 的具体过程\n",
    "        # Step 5: 计算损失函数\n",
    "        return loss, final_status\n",
    "```\n",
    "首先，我们需要创建一个类 `class Net(LoccNet)` 来储存量子系统，与此同时，这个类也继承了 `LoccNet` 中的函数。LOCC 协议的主体部分都是在这个类 `Net()` 中实现的，它包含两个函数：`__init__()` and `forward()`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 `__init__()` 函数中，我们需要初始化所有的参与方、量子态以及 QNN 的参数。\n",
    "\n",
    "- `self.add_new_party(qubits_number, party_name=None)` 是用于添加一个新的参与方的函数，第一个参数代表该参与方有几个量子比特；第二个参数是可选参数，代表着参与者的名字。在协议中，我们可以选择是用过名字来指定参与方，也可以选择用编号来指定。如果我们希望使用名字，那么只需要在 `add_new_party` 函数中给 `party_name` 命名；如果希望使用编号，那么我们就不用给第二个参数赋值，第一个参与方会自动编号为 0，每增加一个参与方，其编号都会加一，同时该函数会将所添加的 party 的 ID 返回，其值根据定义会是 `int` 或者 `str`。\n",
    "\n",
    "- `self.set_init_state(state, which_qubits)` 是用于设置协议的初始态的函数。第一个参数 `state` 是量子态，必须是密度矩阵的形式；第二个参数 `which_qubits` 是定位量子比特（哪一参与方的第几个量子比特，如 `(\"Alice\", 0)`）。需要说明的是，我们必须初始化所有的量子比特，否则程序将出现错误。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 `forward()` 函数中，我们需要定义协议的流程。如果我们想要训练一个模型，那么需要定义损失函数，并设置为 `forward()` 的返回值，这样才能不断更新参数使得损失函数最小化。如果我们仅仅是想要验证某个协议的结果，我们就做上述的事情，只需要把协议的流程定义清除，就可以把我们感兴趣的值设为返回值。在 `forward()` 函数中，我们主要做两件事情--量子操作和测量，我们为他们提供了相应的函数：\n",
    "\n",
    "- `self.create_ansatz(party_id)` 是为某一参与方创建本地量子电路的函数。所以参数 `party_id` 用来指定参与方。举个例子 `cir1 = self.create_ansatz(\"Alice\")` 为 Alice 创建了电路。之后，我们可以在电路中添加不同的操作比如 X 门， CNOT 门等，也可以在添加门之后通过 `run()` 函数来运行电路，得到运行后的结果，如 `status_out = cir1.run(status)`。\n",
    "\n",
    "- `self.measure(status, which_qubits, results_desired, theta=None)` 是用来进行测量的函数。第一个参数 `status` 是我们想要测量的态；第二个参数 `which_qubits` 代表着要测量的是哪一个量子比特。如果我们想测量的是 Alice 手中第 0 个量子比特，那么就需要给第二个参数赋值 `(\"Alice\", 0)`。如果我们想要同时测量两个量子比特，比如 Alice 手中的第 0 个量子比特和 Bob 手中的第 1 个量子比特，那么这个参数需要设为 `[(\"Alice\", 0), (\"Bob\", 1)]`。第三个参数 `results_desired` 是我们希望测量的结果，它只可以为 `\"0\"`，`\"1\"`，或者 `[\"0\", \"1\"]`。第四个参数 `theta` 是用于含参测量，如果我们不希望做含参测量操作，那么就不用给它赋值。\n",
    "\n",
    "- `self.partial_state(status, which_qubits, is_desired=True)` 是用来得到部分量子态的函数。在纠缠蒸馏中，我们可能只有一部分量子态是我们想要的目标态。比如我们想要将 Alice 的第 0 个量子比特和 Bob 的第 0 个量子比特作为目标态，则我们可以通过 `status = self.partial_state(status, [(\"Alice\", 0), (\"Bob\", 0)])`来得到。\n",
    "\n",
    "- `self.reset_state(status, state, which_qubits)` 可以重置部分量子态。有时候我们可能不想使用某些已经测量过的量子态，想将它重置为新的量子态来继续进行 LOCC。因此我们也提供了该功能。\n",
    "\n",
    "- `LoccStatus`：在 `LoccNet` 中，最小的信息单元不是量子态，而是 `LoccStatus`。它包含了量子态，从初始态得到该量子态的概率，以及测量结果。有时候，我们想要得到多个量子态，也就是说我们希望的测量结果是多个，比如在 `self.measure()` 函数中，`results_desired` 设置为 `[\"0\", \"1\"]`。由此，我们能够得到两组 `LoccStatus`，这种情况下，我们的函数返回的是由 `LoccStatus` 组成的 `list`。值得一提的是，不论是 `LoccStatus`，还是由 `LoccStatus` 组成的 `list`，我们的函数几乎都可以对其进行正常执行。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 欢迎使用 LOCCNet！\n",
    "\n",
    "在介绍完上述的 LOCCNet 之后，我们建议您从下面的教程中开始学习如何使用 LOCCNet 框架：\n",
    "\n",
    "- [纠缠蒸馏 -- BBPSSW 协议](EntanglementDistillation_BBPSSW_CN.ipynb)\n",
    "- [纠缠蒸馏 -- DEJMPS 协议](EntanglementDistillation_DEJMPS_CN.ipynb)\n",
    "- [纠缠蒸馏 -- LOCCNet 设计协议](EntanglementDistillation_LOCCNet_CN.ipynb)\n",
    "- [量子隐态传输](QuantumTeleportation_CN.ipynb)\n",
    "- [量子态分辨](StateDiscrimination_CN.ipynb)\n",
    "\n",
    "LOCCNet 框架所能做的远不止上述几个方向，我们希望您可以使用这个新框架去探索更多有趣的协议！"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## 参考文献\n",
    "\n",
    "\n",
    "[1] Chitambar, Eric, et al. \"Everything you always wanted to know about LOCC (but were afraid to ask).\" [Communications in Mathematical Physics 328.1 (2014): 303-326.](https://link.springer.com/article/10.1007/s00220-014-1953-9)\n",
    "\n",
    "[2] Zhao, Xuanqiang, et al. \"LOCCNet: a machine learning framework for distributed quantum information processing.\" [arXiv:2101.12190 (2021).](https://arxiv.org/abs/2101.12190)\n",
    "\n",
    "[3] Bennett, Charles H., et al. \"Teleporting an unknown quantum state via dual classical and Einstein-Podolsky-Rosen channels.\" [Physical Review Letters 70.13 (1993): 1895.](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.70.1895)\n",
    "\n",
    "[4] Bennett, Charles H., et al. \"Purification of noisy entanglement and faithful teleportation via noisy channels.\" [Physical Review Letters 76.5 (1996): 722.](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.76.722)\n",
    "\n",
    "[5] Deutsch, David, et al. \"Quantum privacy amplification and the security of quantum cryptography over noisy channels.\" [Physical Review Letters 77.13 (1996): 2818.](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.77.2818)\n",
    "\n",
    "[6] Zeilinger, Anton, et al. \"Three-particle entanglements from two entangled pairs.\" [Physical Review Letters 78.16 (1997): 3031.](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.78.3031)\n",
    "\n",
    "[7] Zukowski, Marek, et al. \"\" Event-ready-detectors\" Bell experiment via entanglement swapping.\" [Physical Review Letters 71.26 (1993).](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.71.4287)\n",
    "\n",
    "[8] Carleo, Giuseppe, and Matthias Troyer. \"Solving the quantum many-body problem with artificial neural networks.\" [Science 355.6325 (2017): 602-606.](https://science.sciencemag.org/content/355/6325/602)\n",
    "\n",
    "[9] Senior, Andrew W., et al. \"Improved protein structure prediction using potentials from deep learning.\" [Nature 577.7792 (2020): 706-710.](https://www.nature.com/articles/s41586-019-1923-7)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.10"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
